#include "log.hpp"
#include "Sock.hpp"
#include <sys/epoll.h>

const int gsize = 128;
const int num = 256;

class Epoll
{
private:
    int _EpFd;
    int _ListenFd;
    int _port;

public:
    virtual void HandleEvent(epoll_event *revs, int n)
    {
        for (int i = 0; i < n; ++i)
        {
            int sock = revs[i].data.fd;
            uint32_t revents = revs[i].events;
            if (revents & EPOLLIN)
            {
                // 监听套接字
                if (sock == _ListenFd)
                {
                    string ip;
                    uint16_t port;
                    int clientSock = Sock::Accept(_ListenFd, ip, port);
                    if (clientSock < 0)
                    {
                        Log(FATAL, "%d:%s", errno, strerror(errno));
                        continue;
                    }
                    cout << "获取到一个新连接" << ip << ":" << port << endl;
                    // 将新的套接字加入 epoll
                    epoll_event ev;
                    ev.data.fd = clientSock;
                    ev.events = EPOLLIN;
                    int n = epoll_ctl(_EpFd, EPOLL_CTL_ADD, clientSock, &ev);
                    assert(n == 0);
                }
                else
                {
                    char buffer[1024];
                    ssize_t s = recv(sock, buffer, sizeof(buffer) - 1, 0);
                    if (s > 0)
                    {
                        buffer[s] = '\0';
                        Log(NOTICE, "[%d]: %s", sock, buffer);
                    }
                    else
                    {
                        Log(NOTICE, "[%d]: 退出", sock);
                        // 从 epoll中移除
                        epoll_ctl(_EpFd, EPOLL_CTL_DEL, sock, nullptr);
                        close(sock);
                    }
                }
            }
        }
    }
    Epoll(int port)
        : _EpFd(-1), _ListenFd(-1), _port(port)
    {
        // 创建套接字
        _ListenFd = Sock::Socket();
        Sock::Bind(_ListenFd, _port);
        Sock::Listen(_ListenFd);
        // 创建epoll句柄;
        _EpFd = epoll_create(gsize);
        if (_EpFd < 0)
        {
            Log(FATAL, "epoll_create error");
            exit(3);
        }
        // 将监听套接字加入epoll中
        struct epoll_event listenEvent;
        listenEvent.data.fd = _ListenFd;
        listenEvent.events = EPOLLIN;
        epoll_ctl(_EpFd, EPOLL_CTL_ADD, _ListenFd, &listenEvent);
    }
    void Run()
    {
        struct epoll_event *revs = new struct epoll_event[num];
        int timeout = 1000;
        while (true)
        {
            int n = epoll_wait(_EpFd, revs, num, timeout);
            switch (n)
            {
            case 0:
                cout << "time out" << endl;
                break;
            case -1:
                cout << errno << ":" << strerror(errno);
            default:
                HandleEvent(revs, n);
                break;
            }
        }
        delete[] revs;
    }
    ~Epoll()
    {
        if (_ListenFd != -1)
        {
            close(_ListenFd);
        }
        if (_EpFd != -1)
        {
            close(_EpFd);
        }
    }
};

int main(int argc, char* argv[])
{ 
    Epoll server(atoi(argv[1]));
    server.Run();
    return 0;
}